package com.sulent.frame.web.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sulent.frame.file.common.template.MinioTemplate;
import com.sulent.frame.support.exception.BaseException;
import com.sulent.frame.support.exception.BusinessException;
import com.sulent.frame.web.dao.MultiPartDao;
import com.sulent.frame.web.dao.MultiUploadDao;
import com.sulent.frame.web.eneity.MultiPart;
import com.sulent.frame.web.eneity.MultiUpload;
import com.sulent.frame.web.service.MultiUploadService;
import io.minio.MinioClient;
import io.minio.messages.Part;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.List;

/**
 * @ClassName MultiUploadServiceImpl
 * @Description: TODO
 * @Author Submerge.
 * @Since 2024/2/5 11:33
 * @Version 1.0
 */
@Service
public class MultiUploadServiceImpl extends ServiceImpl<MultiUploadDao, MultiUpload> implements MultiUploadService {


    @Autowired
    private MinioTemplate minioTemplate;

    @Autowired
    private MultiPartDao multiPartDao;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public String initMultiUploadTask(String bucketName, String fileName, String fileSize, Integer partCount) {
        String uploadId = minioTemplate.createMultipartUpload(bucketName, fileName);
        MultiUpload multiUpload = new MultiUpload();
        multiUpload.setUploadId(uploadId);
        multiUpload.setBucketName(bucketName);
        multiUpload.setObjectName(fileName);
        multiUpload.setFileSize(Long.valueOf(fileSize));
        multiUpload.setPartCount(partCount);
        multiUpload.setStatus(-2);
        multiUpload.setCreateTime(LocalDateTime.now());
        this.save(multiUpload);
        //初始化分片数量
        for (int i = 1; i <= partCount; i++) {
            MultiPart multiPart = new MultiPart();
            multiPart.setUploadId(uploadId);
            multiPart.setPartNumber(i);
            multiPart.setPartStatus(-2);
            multiPart.setCreateTime(LocalDateTime.now());
            multiPartDao.insert(multiPart);
        }
        return uploadId;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String uploadPart(String uploadId, Long offset, Long length, Integer partNumber, Integer partSize, MultipartFile file) {
        MultiUpload byId = this.getById(uploadId);
        if (byId==null){
            throw new BusinessException("分片任务不存在");
        }
        MultiPart multiPart = multiPartDao.selectOne(new QueryWrapper<MultiPart>().eq("upload_id", uploadId).eq("part_number", partNumber));
        if (multiPart==null){
            throw new BusinessException("该分片不存！");
        }
        try {
            Part part = minioTemplate.uploadPart(uploadId, partNumber, byId.getBucketName(), byId.getObjectName(), file.getInputStream());
            multiPart.setEtag(part.etag());
            multiPart.setPartNumber(part.partNumber());
//            multiPart.setPartSize(part.partSize());
        } catch (IOException e) {
            e.printStackTrace();
        }
        multiPart.setPartSize(file.getSize());
        multiPart.setOffset(offset);
        multiPart.setLength(length);
        multiPart.setPartStatus(2);
        multiPart.setUpdateTime(LocalDateTime.now());
        multiPartDao.updateById(multiPart);
        return multiPart.getEtag();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String completePart(String uploadId) {
        MultiUpload byId = this.getById(uploadId);
        if (byId==null){
            throw new BusinessException("分片任务不存在");
        }
        List<MultiPart> multiParts = multiPartDao.selectList(new QueryWrapper<MultiPart>().eq("upload_id", uploadId));
        long count = multiParts.stream().filter(multiPart -> multiPart.getPartStatus() == 2).count();
        if (byId.getPartCount() != count){
            throw new BusinessException("分片未上传完整，不能合并！");
        }
        Part[] parts = new Part[1000];
        for (MultiPart multiPart : multiParts){
            parts[multiPart.getPartNumber()] = new Part(multiPart.getPartNumber(), multiPart.getEtag());
        }
        minioTemplate.completeMultipartUpload(uploadId,parts,byId.getBucketName(),byId.getObjectName());
        //合并成功后修改任务状态
        byId.setStatus(2);
        this.updateById(byId);
        return "over!";
    }

    @Override
    public List<Part> listMulti(String uploadId) {
        MultiUpload byId = this.getById(uploadId);
        if (byId==null){
            throw new BusinessException("分片任务不存在");
        }
        List<Part> parts = minioTemplate.listParts(uploadId, byId.getPartCount(), byId.getBucketName(), byId.getObjectName());
        return parts;
    }

    @Override
    public String downloadObject(String objectName) {
        File file = minioTemplate.downloadObject("ai-model", objectName);
        return file.getAbsolutePath();
    }

    @Override
    public Object listMultiUploads(String uploadId) {
        MultiUpload byId = this.getById(uploadId);
        if (byId==null){
            throw new BusinessException("分片任务不存在");
        }
        return minioTemplate.listMultiUpload(byId.getBucketName());
    }

    @Override
    public String stateObject(String objectName) {
        return minioTemplate.statObject(null, objectName);
    }

    @Override
    public String preSignedUrl(String objectName) {
        return minioTemplate.getPreSignedObjectUrl("ai-model",objectName);
    }
}
